/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */

package dtd.to.xml;

import java.util.Objects;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import org.apache.commons.lang3.StringUtils;

/**
 * Class which represents one parsed DTD Element
 * @author martin
 */
public class DTDElement {
    private final String name;
    private String info;    
    
    /**
     * Constructor
     * @param newName name of element
     * @param newInfo type of element or children of elements
     */
    public DTDElement(String newName , String newInfo){
        name = newName;        
        info = newInfo;
        prepareInfo();            
    }
    /**
     * Getter for element name
     * @return element name
     */
    public String getName(){
        return name;
    }
    /**
     * Getter for element info
     * @return element info
     */  
    public String getInfo(){
        return info;
    }

    @Override
    public int hashCode() {
        int hash = 7;
        hash = 29 * hash + Objects.hashCode(name);
        hash = 29 * hash + Objects.hashCode(info);
        return hash;
    }

    @Override
    public boolean equals(Object obj) {
        if (obj == null) {
            return false;
        }
        if (getClass() != obj.getClass()) {
            return false;
        }
        final DTDElement other = (DTDElement) obj;
        if (!Objects.equals(name, other.name)) {
            return false;
        }
        if (!Objects.equals(info, other.info)) {
            return false;
        }
        return true;
    }
 
    private void prepareInfo(){           
        info = info.replaceAll("\\s+", "");        
        while(info.startsWith("(") && !info.substring(info.length()-1).matches("[*+?]")){
            info = info.substring(1, info.length()-1);
        }        
        removerWithoutOccurs();
        info = onlyOneChild(info);        
        info = removeUnwanted(info,"*");
        info = removeUnwanted(info,"+");
        info = removeUnwanted(info,"?");        
        if(info.contains(",") || info.contains("|")){
            info = divideAndRemove(",",info);
            info = divideAndRemove("\\|",info);        
        }
        
        Pattern pattern = Pattern.compile("[(]+(\\w+([,|]\\w+)*[)])+[|,]([(]*\\w+([,|]\\w+[)])*)[)]+[^*+?]");
        Matcher matcher = pattern.matcher(info);        
        if (matcher.find()){            
            String tmp = "";
            for(int i = 0; i < matcher.groupCount() -3;i++){
                tmp += matcher.group(i);
            }                      
        info = info.replaceAll("[(]+(\\w+([,|]\\w+)*[)])+[|,]([(]*\\w+([,|]\\w+[)])*)[)]+[^*+?]",removeUnwanted(tmp.substring(0, tmp.length() -1),"") + ",");                        
        info = info.replaceAll("[(]+(\\w+([,|]\\w+)*[)])+[|,]([(]*\\w+([,|]\\w+[)])*)[)]+[^*+?]",divideAndRemove("\\|",tmp.substring(0, tmp.length() -1)) + ",");                        
        info = info.replaceAll("[(]+(\\w+([,|]\\w+)*[)])+[|,]([(]*\\w+([,|]\\w+[)])*)[)]+[^*+?]",divideAndRemove(",",tmp.substring(0, tmp.length() -1)) + ",");                                
        }                                
    }
    
    private void removerWithoutOccurs(){
        Pattern p = Pattern.compile("[+*?]");
        Matcher m = p.matcher(info); 
        if(!info.contains("|") && info.contains(",") && !m.find()){
            info = StringUtils.remove(info, "(");
            info = StringUtils.remove(info, ")");
        }
        if(info.contains("|") && !info.contains(",") && !m.find()){
            info = StringUtils.remove(info, "(");
            info = StringUtils.remove(info, ")");
        }        
    }
    
    private String removeUnwanted(String input, String ending){
        int count = 0;        
        if(ending.equals(""))
            count = 1;
        else
            count = StringUtils.countMatches(input, ending);                
        
        if(count == 1 && (input.contains("|") || input.contains(",")) && input.endsWith(ending)){            
            String end = "";
            if(!ending.equals("")){
                end = input.substring(input.length()-1);
                input = input.substring(0, input.length()-1);
            }
            int rounds = 0;
            while(input.startsWith("(") && input.endsWith(")")){
                input = input.substring(1, input.length()-1);   
                rounds++;
            }            
            if (rounds != 0 || input.contains("("))
                input = "(" + input + ")" + end;                            
            else
                input = input + end;                            
        }                
        return input;
    }
    
    private String onlyOneChild(String input){          
        String end = "";
        if(input.substring(input.length() - 1).matches("[*+?]")){              
            end = input.substring(input.length() - 1);
            input = input.substring(0, input.length() - 1);
        }
        while(input.matches("[(]+\\w+([)]+[*+?][)])+")){
            if(count(input) >= 1){                
                end = input.substring(input.length() - 1) + end;
                input = input.substring(0, input.length() - 1);                
            }
        }
        if(input.substring(input.length() - 1).matches("[*+?]")){
            end = input.substring(input.length() - 1) + end;
            input = input.substring(0, input.length() - 1);
        }
        
        if(!input.contains("|") && !input.contains(",")){            
            while(input.startsWith("(") && input.endsWith(")")){
                input = input.substring(1, input.length() -1);                
            }
        }        
        return input + end;
    }
    private String divideAndRemove(String splitter , String input){        
        String[] split = input.split(splitter);        
        
        if(split[0].equals(input))
            return input;
        if(splitter.contains("|"))
            splitter = splitter.substring(1);   
        String output = "";
        for(String s : split){                  
            if(s.startsWith("("))
                s = onlyOneChild(s);              
            output += s + splitter;
        }            
        return output.substring(0,output.length() - 1);
    }
    
    private int count(String input){
        Pattern p = Pattern.compile("[+*?]");
        Matcher m = p.matcher(input);
        int count = StringUtils.countMatches(input, "+");
        count += StringUtils.countMatches(input, "*");
        count += StringUtils.countMatches(input, "?");        
        return count;
    }
}
